package com.example.glesstudy;

import android.content.Context;
import android.opengl.GLES11Ext;
import android.opengl.GLES20;
import android.util.Log;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import static android.opengl.GLES20.*; // 静态引入

public class ScreenFilter {

    private final int vPosition;
    private final int vCoord;
    private final int vMatrix;
    private final int vTexture;
    private final FloatBuffer vertexBuffer;
    private final FloatBuffer textureBuffer;
    private final int program;

    private int width;
    private  int height;

    public ScreenFilter(Context context) {

        String vertexSource = readTextFileFromResource(context,R.raw.camera_vertex);
        // 片元 代码字符串
        String fragemntSource = readTextFileFromResource(context,R.raw.camera_fragemnt);

        //TODO 1  创建顶点着色器
        int vshaderId = glCreateShader(GLES20.GL_VERTEX_SHADER);
        //绑定代码 到着色器
        glShaderSource(vshaderId,vertexSource);
        //编译着色器代码
        glCompileShader(vshaderId);
        int[] status = new int[1];
        // 检查编译状态是否有异常
        glGetShaderiv(vshaderId,GL_COMPILE_STATUS,status,0);
        if (status[0] != GL_TRUE) {
            throw  new IllegalStateException("顶点着色器配置失败");
        }

        //TODO 2 创建片元着色器
        int fshaderId = glCreateShader(GL_FRAGMENT_SHADER);
        //绑定代码 到着色器
        glShaderSource(fshaderId,fragemntSource);
        //编译着色器代码
        glCompileShader(fshaderId);
        // 检查编译状态是否有异常
        glGetShaderiv(vshaderId,GL_COMPILE_STATUS,status,0);
        if (status[0] != GL_TRUE) {
            throw  new IllegalStateException("片元着色器配置失败");
        }

        /**
         * TODO 3，配置着色器程序
         */
        // 3.1 创建一个着色器程序
        program = glCreateProgram();
        // 3.2 将前面配置的 顶点 和 片元 着色器 附加到新的程序 上
        glAttachShader(program, vshaderId); // 顶点
        glAttachShader(program, fshaderId); // 片元
        // 3.3 链接着色器
        glLinkProgram(program); // mProgram着色器程序 是我们的成果
        glGetProgramiv(program, GL_LINK_STATUS, status, 0);
        if (status[0] != GL_TRUE) {
            throw new IllegalStateException("着色器程序链接失败----"+glGetProgramInfoLog(program));
        }
        // ToDO 4 释放 删除着色器  因为用不到了program 有着色器程序 就可以了
        glDeleteShader(vshaderId);
        glDeleteShader(fshaderId);

        // 获取变量的索引值 通过索引来赋值
        // 顶点着色器里面的 索引值
        vPosition =glGetAttribLocation(program,"vPosition");// 顶点着色器 索引值
        vCoord =glGetAttribLocation(program,"vCoord");// 纹理坐标
        vMatrix =glGetUniformLocation(program,"vMatrix");// 变换矩阵

        // 片元着色器
        vTexture =glGetUniformLocation(program,"vTexture");// 采样器

        //NIO Buffer 就是一个缓存 存 和 取  着色器语言绑定

        // 顶点坐标缓存（顶点位置 排版）---vPosition
         vertexBuffer = ByteBuffer.allocateDirect(4 * 2 * 4) // 分配内存 坐标个数 * 2个 * float占用4个字节
                .order(ByteOrder.nativeOrder())// 使用本地字节序列/ 例如 大端 小端  这里设置位 跟随OpenGL 的变化变化
                .asFloatBuffer();
         vertexBuffer.clear();// 清除一下

        float[] v= { // opengl 世界坐标
          -1.0f,-1.0f,
          1.0f, -1.0f,
          -1.0f,1.0f,
          1.0f,1.0f
        };
        vertexBuffer.put(v);
        // 纹理坐标缓存（顶点位置 排版）---vCoord
        textureBuffer = ByteBuffer.allocateDirect(4 * 2 * 4) // 分配内存 坐标个数 * 2个 * float占用4个字节
                .order(ByteOrder.nativeOrder())// 使用本地字节序列/ 例如 大端 小端  这里设置位 跟随OpenGL 的变化变化
                .asFloatBuffer();
        textureBuffer.clear();// 清除一下

        float[] t  = { // 屏幕坐标
                0.0f,1.0f,
                1.0f,1.0f,
                0.0f,0.0f,
                1.0f,0.0f
        };
        textureBuffer.put(t);


    }

    public void onReady(int width, int height) {

        this.width = width;
        this.height = height;
    }

    public void onDrawFrame(int mTextureId, float[] mtx) {

        // 设置视窗大小 从 0 开始  这个时合理的
        glViewport(0,0, width,height);
        glUseProgram(program);// 执行着色器程序

        // 绘制工作
        //todo 顶点坐标赋值  NIO 的 Buffer 用它就要归零 习惯
        vertexBuffer.position(0);

        /**
         * 给顶点 传值 opengl 世界坐标
         * 传值 把float 值 传递给着色器 每次2个xy 不跳步
         * 着色器 vPosition  标记变量
         * xy 所以是 2
         * 3
         * 4 0 不跳步跳0步
         */
        glVertexAttribPointer(vPosition,2,GL_FLOAT,false,0,vertexBuffer);

        // 激活
        glEnableVertexAttribArray(vPosition);

        // 纹理坐标赋值 屏幕坐标
        textureBuffer.position(0);
        glVertexAttribPointer(vCoord,2 ,GL_FLOAT,false,0,textureBuffer);
        glEnableVertexAttribArray(vCoord);

        // 变换矩阵
        glUniformMatrix4fv(vMatrix,1,false,mtx,0);

        //片元
        // 激活图层
        glActiveTexture(GL_TEXTURE);

        // 绑定纹理ID
        //GL_TEXTURE_2D 配合 另外一个
        //GL_TEXTURE_EXTERNAL_OES 配合 samplerExternalOES
        glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,mTextureId);
        glUniform1f(vTexture,0);// 传递参数 给片元 采样器

        //通知opengl 绘制 从0 开始 共 4个点绘制
        glDrawArrays(GL_TRIANGLE_STRIP,0,4);

    }

    private static String readTextFileFromResource(Context context,int resId) {
        StringBuilder stringBuilder = new StringBuilder();
        InputStream inputStream = context.getResources().openRawResource(resId);
        InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
        BufferedReader br = new BufferedReader(inputStreamReader);
        String newLine;
        try{
            while ((newLine = br.readLine())!=null) {
                stringBuilder.append(newLine);
                stringBuilder.append("\n");
            }
        }catch (Exception e) {
            Log.e("Exception",e.getMessage());
        }

        return stringBuilder.toString();
    }
}
